package com.javaProject.service.impl;
import com.javaProject.entity.SM2Util;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.math.ec.ECPoint;
import org.springframework.stereotype.Service;


import java.nio.charset.StandardCharsets;
import java.security.*;


@Service
public class SM2 {

    private static final ECNamedCurveParameterSpec sm2Spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
    public static final ECDomainParameters domainsParams = new ECDomainParameters(sm2Spec.getCurve(), sm2Spec.getG(), sm2Spec.getN(), sm2Spec.getH());

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public String encrypt(String password, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        byte[] encryptedPassword = encryptWithSM2(password, publicKey);
        return bytesToHex(encryptedPassword);
    }

    public String decrypt(String encryptedPassword, PrivateKey privateKey) {
        byte[] encryptedBytes = hexToBytes(encryptedPassword);
        byte[] decryptedBytes = decryptWithSM2(encryptedBytes, privateKey);
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }

    private byte[] encryptWithSM2(String password, PublicKey publicKey) {
        try {

            // 获取ECPoint
            ECPoint point = ((ECPublicKey) publicKey).getQ();

            // 创建ECPublicKeyParameters
            ECDomainParameters domainParams = domainsParams;
            if (domainParams == null) {
                throw new IllegalArgumentException("ECDomainParameters cannot be null.");
            }
            ECPublicKeyParameters params = new ECPublicKeyParameters(point, domainParams);

            // 使用ParametersWithRandom包装ECPublicKeyParameters
            ParametersWithRandom parametersWithRandom = new ParametersWithRandom(params, new SecureRandom());

            // 初始化SM2Engine
            SM2Engine engine = new SM2Engine();
            engine.init(true, parametersWithRandom);

            byte[] input = password.getBytes(StandardCharsets.UTF_8);
            return engine.processBlock(input, 0, input.length);
        } catch (Exception e) {
            e.printStackTrace();  // 可以记录到日志文件中
            return new byte[0];   // 或者返回空字节数组，而不是 null
        }
    }

    private byte[] decryptWithSM2(byte[] encryptedBytes, PrivateKey privateKey) {
        try {
            if (encryptedBytes == null || privateKey == null) {
                throw new IllegalArgumentException("Encrypted data and private key should not be null");
            }

            // 初始化SM2Engine
            SM2Engine engine = new SM2Engine();
            // 使用私钥参数初始化SM2Engine
            engine.init(false, SM2Util.generatePrivateKeyParameters(privateKey));

            return engine.processBlock(encryptedBytes, 0, encryptedBytes.length);
        } catch (Exception e) {
            // 记录异常及相关信息到日志文件中
            System.out.println("Error occurred during SM2 decryption: " + e.getMessage());
            // 或者抛出自定义异常来提供更多上下文信息
            throw new IllegalStateException("Error occurred during SM2 decryption", e);
        }
    }


    private String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    private byte[] hexToBytes(String hexString) {
        int len = hexString.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        return data;
    }
    public KeyPair generateKeyPair() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "BC");
        keyGen.initialize(sm2Spec, new SecureRandom());
        return keyGen.generateKeyPair();
    }
}
